﻿
// opencv_demo1.cpp: 定义应用程序的类行为。
//

#include "pch.h"
#include "opencv_fun.h"


#include <opencv2\opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2\imgproc\types_c.h>
#include <opencv2/imgcodecs.hpp>

using namespace cv;
using namespace std;

#include "watermask_cv_dct.h"

void opencv_start()
{
	open_format_test();     //mat格式转换测试
	//opencv_dct_yuv_show();
	//opencv_dct_demo1();    //dct 用法测试
	//dct_picture_zip();     //图片压缩
	//dct_waterMark_test();  //水印测试
	//createPic();    //创建图片测试
}
void dct_waterMark_test()
{
	//dct 算法添加水印和提取测试
	Mat img = imread("C:/Users/hanbo/Desktop/test/host.jpg");//加载图片
	cv::resize(img, img, cv::Size(640, 480));

	imshow("原图", img);

	watermask_cv_dct testimg;
	testimg.loadWatermask();
	Mat outImg = testimg.addImageWatermarkWithText(img);
	imwrite("stzz-out.jpg", outImg);//保存加过水印的图片
	imshow("addwaterImg", outImg);

	{
		watermask_cv_dct testimg2;
		Mat watermarkImg = testimg2.getImageWatermarkWithText(outImg);
		imshow("水印outImg", watermarkImg);
	}


	//Mat waterimg = imread("stzz-out.jpg");//加载图片
	//imshow("添加水印保存文件加载", waterimg);
	////读取图片水印
	//watermask_cv_dct testimg2;
	//Mat watermarkImg = testimg2.getImageWatermarkWithText(outImg);
	//cv::resize(watermarkImg, watermarkImg, cv::Size(128, 128));
	//imshow("水印文件中", watermarkImg);

#if 0
	Mat img = imread("C:/Users/hanbo/Desktop/test/host.jpg");//加载图片
	imshow("原图", img);
	watermask_cv_dct testimg;
	Mat outImg = testimg.addImageWatermarkWithText(img, "testwatermarkhano");
	imwrite("stzz-out.jpg", outImg);//保存加过水印的图片

	{
		watermask_cv_dct testimg2;
		Mat watermarkImg = testimg2.getImageWatermarkWithText(outImg);
		imshow("水印outImg", watermarkImg);
	}


	Mat waterimg = imread("stzz-out.jpg");//加载图片
	imshow("添加水印", waterimg);
	//读取图片水印
	watermask_cv_dct testimg2;
	Mat watermarkImg = testimg2.getImageWatermarkWithText(waterimg);
	imshow("水印", watermarkImg);
#endif
}
void open_format_test()
{
	if(0)
	{
		std::vector<Mat> channels;
		// 读入一张图片（游戏原画）  
		Mat src = imread("host.jpg");
		imshow("Origin Image", src);

		//结论： yuv——I420 不能直接显示。只能显示Y或转换为rgb显示
		//yuv显示
		Mat origYUV;
		cv::cvtColor(src, origYUV, CV_BGR2YUV);
		namedWindow("origyuv", WINDOW_NORMAL);
		imshow("origyuv", origYUV);

		split(origYUV, channels);
		imshow("origy", channels.at(0));
		imshow("origu", channels.at(1));
		waitKey();
	}
	if(1)
	{
		//通过yuv内存数据，生成mat
		FILE* pyufile = fopen("testpic_640_480.yuv","rb");
		char* buf = new char[640 * 480 * 3 / 2];
		fread(buf, 1, 640 * 480 * 3 / 2, pyufile);
		fclose(pyufile);
		cv::Mat yuvImg(480+480/2, 640, CV_8UC1, buf);
		cv::imshow("pyufile", yuvImg);

		cv::Mat yuvgbr;
		cv::cvtColor(yuvImg, yuvgbr,CV_YUV2BGRA_I420);
		cv::imshow("YUV2BGRA_I420", yuvgbr);
	}
	
	if(0)
	{
		//灰度图，黑白图
		std::vector<Mat> channels;
		// 读入一张图片（游戏原画）  
		Mat src = imread("host.jpg");
		imshow("Origin Image", src);

		Mat grayImg;
		cvtColor(src, grayImg, CV_BGR2GRAY);
		imshow("gray img", grayImg);

		//图片拷贝
		//Mat grayImg_new(grayImg.rows,grayImg.cols, THRESH_BINARY);
		cv::threshold(grayImg, grayImg, 128, 255, THRESH_BINARY);

		Mat grayImg_new(grayImg.rows, grayImg.cols, CV_8UC1);
		for (int i = 0; i < grayImg.rows; i++) {
			for (int j = 0; j < grayImg.cols; j++) {
				grayImg_new.at<uchar>(i, j) = grayImg.at<uchar>(i, j);
			}
		}
		
		Mat bgrimg;
		cv::cvtColor(grayImg_new, bgrimg, CV_GRAY2BGR);
		split(bgrimg, channels);
		Mat YUVIMG(grayImg_new.rows + grayImg_new.rows/2, grayImg_new.cols,CV_8UC1);  //构造yuv空间
		cv::cvtColor(bgrimg, YUVIMG, CV_BGR2YUV_I420);
		//split(YUVIMG, channels);
		//imshow("bgrimg", bgrimg);
		//imshow("YUVy", channels[0]);

		FILE* pfile = fopen("newimg.yuv", "wb");
		fwrite(YUVIMG.data, 1, bgrimg.cols * bgrimg.rows * 3 / 2, pfile);
		fclose(pfile);

		imwrite("graynew.bmp", grayImg_new);	
	}
}
void opencv_dct_demo1()
{
	Mat src;
	src = imread("C:/Users/hanbo/Desktop/test/host.jpg");;
	if (src.empty()) // Check for invalid input
	{
		return;
	}
	//resize(src, src, Size(8, 8));

	vector<Mat> channels;
	split(src, channels);

	Mat DCTb(src.size(), CV_64FC1);
	Mat DCtg(src.size(), CV_64FC1);
	Mat DCTr(src.size(), CV_64FC1);
	//DCT变换    
	dct(Mat_<double>(channels.at(0)), DCTb, 0);
	dct(Mat_<double>(channels.at(1)), DCtg, 0);
	dct(Mat_<double>(channels.at(2)), DCTr, 0);
	
	vector<Mat> dctchannels(3);
	dctchannels.at(0) = Mat_<uchar>(DCTb);
	dctchannels.at(1) = Mat_<uchar>(DCtg);
	dctchannels.at(2) = Mat_<uchar>(DCTr);

	Mat outimg(src.size(), CV_64FC3);
	merge(dctchannels, outimg);

	imshow("src", src);
	imshow("dct", outimg);

	//cout << channels.at(0) << endl;
	//cout << Mat_<int>(DCTb) << endl;

	waitKey();
}


void opencv_dct_yuv_show()
{
	//https://blog.csdn.net/akadiao/article/details/79778095
	//显示yuv分量和dct效果
	Mat srcImage;
	srcImage = imread("C:/Users/hanbo/Desktop/test/host.jpg"); // Read the file
	if (srcImage.empty()) // Check for invalid input
	{
		return;
	}
	resize(srcImage, srcImage, cv::Size(16, 16));

	//namedWindow("Display window", WINDOW_NORMAL); // Create a window for display.
	//imshow("Display window", image); // Show our image inside it.

	//namedWindow("原图像", WINDOW_NORMAL);
	imshow("原图像", srcImage);
	int height = srcImage.rows;
	int width = srcImage.cols;

	//从BGR空间转换到YUV颜色空间
	Mat yuvImage(srcImage.size(), CV_8UC3);
	cvtColor(srcImage, yuvImage, CV_BGR2YUV);   //yuv dct
	//yuvImage = srcImage;    //bgr dct

	//分割YUV三个通道
	vector<Mat> channels;
	split(yuvImage, channels);

	//提取YUV颜色各个通道的值
	Mat y = channels.at(0);
	//imshow("Y", y);
	Mat u = channels.at(1); 
	//imshow("U", u);
	Mat v = channels.at(2);
	//imshow("V", v);

	//定义DCT系数的三个通道
	Mat DCTY(srcImage.size(), CV_64FC1);
	Mat DCTU(srcImage.size(), CV_64FC1);
	Mat DCTV(srcImage.size(), CV_64FC1);

	//进行DCT变换
	dct(Mat_<double>(y), DCTY);
	//imshow("dct_y", DCTY);
	dct(Mat_<double>(u), DCTU);
	dct(Mat_<double>(v), DCTV);

	channels.at(0) = Mat_<uchar>(DCTY);
	channels.at(1) = Mat_<uchar>(DCTU);
	channels.at(2) = Mat_<uchar>(DCTV);

	//定义输出图像
	Mat dstImage(srcImage.size(), CV_64FC3);
	merge(channels, dstImage);
	imshow("DCT图像", dstImage);

	cout << y << endl;
	cout << Mat_<int>(DCTY) << endl;
	cout << Mat_<uchar>(DCTY) << endl;
	cout << Mat_<uchar>(dstImage) << endl;
}


static bool g_printdata = true;  //是否显示矩阵内容，最好修改为8x8。否则控制台显示有问题
void dct_picture_zip()
{
	//使用dct 进行图片压缩
	static double T = 75;  //压缩深度

	// 读入一张图片（游戏原画）  
	Mat src = imread("C:/Users/hanbo/Desktop/test/host.jpg");
	//resize(src, src, Size(src.cols / 2 * 2, src.rows / 2 * 2));
	resize(src, src, Size(8, 8));
	imshow("Origin Image", src);

	int h = src.rows;
	int w = src.cols;

	//Mat yuvimg = src.clone();
	//从BGR空间转换到YUV空间（也可以不转换，直接在RGB空间）      
	Mat yuvimg(src.size(), CV_8UC3);
	cvtColor(src, yuvimg, CV_BGR2YUV); //定义YUV空间图像为yuvimage    
	Mat dst(src.size(), CV_64FC3);     //定义输出图像为dst    

									  
	vector<Mat> channels;
	split(yuvimg, channels);  //分割YUV通道    

	//提取YUV颜色空间各通道      
	Mat Y = channels.at(0);
	//imshow("Y image", Y);
	Mat U = channels.at(1);
	//imshow("U image", U);
	Mat V = channels.at(2);
	//imshow("V image", V);

	//DCT系数的三个通道    
	Mat DCTY(yuvimg.size(), CV_64FC1);
	Mat DCTU(yuvimg.size(), CV_64FC1);
	Mat DCTV(yuvimg.size(), CV_64FC1);
	//DCT变换    
	dct(Mat_<double>(Y), DCTY, 0);
	dct(Mat_<double>(U), DCTU, 0);
	dct(Mat_<double>(V), DCTV, 0);

	if (g_printdata)
	{
		cout << "Y orig:" << endl;
		cout << Y << endl;
		//显示
		cout << "dctY orig:" << endl;
		cout << Mat_<int>(DCTY) << endl;
	}	

	//Y通道压缩      
	for (int i = 0; i < h; i++)
	{
		double* p = DCTY.ptr<double>(i);
		for (int j = 0; j < w; j++)
		{
			if (i == 0 && j == 0) {
				printf("y orig: %f\n", p[j]);
				p[j] = p[j] - 100;
			}
			if (abs(p[j]) < T)
				p[j] = 0;
		}
	}

	//U通道压缩      
	for (int i = 0; i < h; i++)
	{
		double* p = DCTU.ptr<double>(i);
		for (int j = 0; j < w; j++)
		{
			if (abs(p[j]) < T)
				p[j] = 0;
		}
	}

	//V通道压缩      
	for (int i = 0; i < h; i++)
	{
		double* p = DCTV.ptr<double>(i);
		for (int j = 0; j < w; j++)
		{
			if (abs(p[j]) < T)
				p[j] = 0;
		}
	}

	if (g_printdata) {
		cout << "dctY modify:" << endl;
		cout << Mat_<int>(DCTY) << endl;
	}
	

	Mat dstY(src.size(), CV_64FC1);
	Mat dstU(src.size(), CV_64FC1);
	Mat dstV(src.size(), CV_64FC1);

	//DCT逆变换    
	idct(DCTY, dstY);
	idct(DCTU, dstU);
	idct(DCTV, dstV);

	//merge方式1    
	//Mat planes[] = { Mat_<uchar>(dstB), Mat_<uchar>(dstG), Mat_<uchar>(dstR) };    
	//merge(planes, 3, yuvimg);     
	//cvtColor(yuvimg, dst, CV_YUV2BGR);    

	//merge方式2    
	channels.at(0) = Mat_<uchar>(dstY);
	channels.at(1) = Mat_<uchar>(dstU);
	channels.at(2) = Mat_<uchar>(dstV);

	if (g_printdata) {
		cout << "new Y:" << endl;
		cout << channels.at(0) << endl;
	}

	merge(channels, yuvimg);

	//将压缩后图像从YUV空间重新转换到BGR空间    
	cvtColor(yuvimg, dst, CV_YUV2BGR);

	//imshow("Recoverd Y image", Mat_<uchar>(dstY));
	//imshow("Recoverd U image", Mat_<uchar>(dstU));
	//imshow("Recoverd V image", Mat_<uchar>(dstV));
	imshow("DstImage", dst);
	stringstream s;
	s << T;
	std::string t = s.str();
	std::string outname = string("C:/Users/hanbo/Desktop/test/DstImage") + t + ".jpg";
	imwrite(outname, dst);

	dct_picture_unzip(outname);

	waitKey(0);
}

void dct_picture_unzip(std::string outname)
{
	static double T = 10;

	// 读入一张图片（游戏原画）  
	Mat src = imread(outname);
	imshow("unzip Origin Image", src);
	int h = src.rows;
	int w = src.cols;

	//Mat yuvimg = src.clone();
	//从BGR空间转换到YUV空间（也可以不转换，直接在RGB空间）      
	Mat yuvimg(src.size(), CV_8UC3);
	cvtColor(src, yuvimg, CV_BGR2YUV); //定义YUV空间图像为yuvimage    
										
	vector<Mat> channels;
	split(yuvimg, channels);  //分割YUV通道    

	//提取YUV颜色空间各通道      
	Mat Y = channels.at(0);
	imshow("Y image", Y);
	//waitKey(0);
	//DCT系数的三个通道，只处理y
	Mat DCTY(yuvimg.size(), CV_64FC1);
	//Mat DCTU(yuvimg.size(), CV_64FC1);
	//Mat DCTV(yuvimg.size(), CV_64FC1);
	//DCT变换    
	dct(Mat_<double>(Y), DCTY, 0);

	//显示
	if (g_printdata) {
		cout << "unzip Y orig:" << endl;
		cout << Y << endl;

		cout << "unzip dctY orig:" << endl;
		cout << Mat_<int>(DCTY) << endl;
	}
	

	waitKey(0);
	
}

void createPic()
{
	//Mat m2(120, 120, CV_8UC3, Scalar(0, 255, 0));//创建120×120的三通道图像，指定图像的像素值
	//cv::imshow("create_m2",m2);

	Mat m2(500, 500, CV_8UC3, Scalar(0,0, 0));//创建120×120的三通道图像，指定图像的像素值
	cv::imshow("create_m1", m2);

	Mat yuv;
	cvtColor(m2, yuv, CV_BGR2YUV);
	cv::imshow("create_yuv", yuv);

	std::vector<Mat> yuvs;
	split(yuv, yuvs);
	cv::imshow("create_yuvssss", yuvs.at(0));
}